package com.csf.habook.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.csf.dto.resp.FindUserByPhoneRspDTO;
import com.csf.fromwork.common.eumns.DeletedEnum;
import com.csf.fromwork.common.eumns.StatusEnum;
import com.csf.fromwork.common.exception.BizException;
import com.csf.fromwork.common.response.Response;
import com.csf.fromwork.common.util.JsonUtils;
import com.csf.habook.auth.constant.RedisKeyConstants;

import com.csf.habook.auth.enums.LoginTypeEnum;
import com.csf.habook.auth.enums.ResponseCodeEnum;


import com.csf.habook.auth.model.vo.user.UpdatePasswordReqVO;
import com.csf.habook.auth.model.vo.user.UserLoginReqVO;
import com.csf.habook.auth.rpc.UserRpcService;
import com.csf.habook.auth.service.AuthService;


import com.csf.holder.LoginUserContextHolder;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.awt.image.RescaleOp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * @author sss
 */

@Service
@Slf4j
public class AuthServiceImpl implements AuthService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;;
    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserRpcService userRpcService;

    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        String phone = userLoginReqVO.getPhone();
        Integer type = userLoginReqVO.getType();

        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);

        // 用户id
        Long userId = null;
        switch (Objects.requireNonNull(loginTypeEnum)) {
            case VERIFICATION_CODE:// 验证码登录
                String code = userLoginReqVO.getCode();

                // 判断验证码是否为空
                Preconditions.checkArgument(StringUtils.isNotBlank(code), "验证码不能为空");


                // 构建验证码 Redis Key
                String key = RedisKeyConstants.buildVerificationCodeKey(phone);
                // 查询储存在redis中的对应的值
                String sentKey = (String) redisTemplate.opsForValue().get(key);

                // 判断验证码是否正确
                if (!StringUtils.equals(code, sentKey)) {
                    throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                }

                // RPC: 调用用户服务，注册用户
                Long userIdTmp = userRpcService.registerUser(phone);

                // 若调用用户服务，返回的用户 ID 为空，则提示登录失败
                if (Objects.isNull(userIdTmp)) {
                    throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                }

                userId = userIdTmp;

                break;
            case PASSWORD:
                // 拿到密码
                String password = userLoginReqVO.getPassword();

                // RPC: 调用用户服务，通过手机号查询用户
                FindUserByPhoneRspDTO findUserByPhoneRspDTO = userRpcService.findUserByPhone(phone);


                if (Objects.isNull(findUserByPhoneRspDTO)) {
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }
                // 拿到密文密码
                String encodePassword = findUserByPhoneRspDTO.getPassword();

                // 匹配密码是否一致
                boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);

                // 如果不正确，则抛出业务异常，提示用户名或者密码不正确
                if (!isPasswordCorrect) {
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }

                userId = findUserByPhoneRspDTO.getId();
                break;
            default:
                break;
        }

        // saToken登录用户并返回token
        StpUtil.login(userId);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return Response.success(tokenInfo.tokenValue);
    }

    @Override
    public Response<?> logOut() {
        Long userId = LoginUserContextHolder.getUserId();

        threadPoolTaskExecutor.submit(() -> {
            Long userId2 = LoginUserContextHolder.getUserId();
            log.info("==> 异步线程中获取 userId: {}", userId2);
        });

        log.info("==> 用户退出登录, userId: {}", userId);
        StpUtil.logout(userId);
        return Response.success();
    }


    /*
     * 修改密码
     * */
    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        // 获得新密码
        String newPassword = updatePasswordReqVO.getNewPassword();
        // 对密码进行加密
        String encodePassword = passwordEncoder.encode(newPassword);

        // RPC:调用用户服务 更新密码
        userRpcService.updatePassword(encodePassword);
        return Response.success();
    }
}
